<?php
/**
Plugin Name: EventPostType
Plugin URI: http://URI_Of_Page_Describing_Plugin_and_Updates
Description: A Plugin for Wordpress which creates a new post type for Events
Version: 1.1
Author: Peter Edwards
Author URI: http://bjorsq.net
License: GPL2
*/

/*  Copyright 2011  Peter Edwards  (email : p.l.edwards@leeds.ac.uk)

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License, version 2, as 
    published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

if (!class_exists('EventPostType')) :
/**
 * Class to create a custom post type for events
 * Adds the custom post type and additional editing fields for
 * the post editor to handle custom event properties. Provides
 * methods to use in templates and feeds
 * @author Peter Edwards <tech@e-2.org>
 * @version 1.1
 * @package WordPress
 * @subpackage EventPostType_Plugin
 */
class EventPostType
{
    /**
	 * @var version
	 */
	public static $version = '1.1';
    /**
     * this is used to back port all events in the system to save
     * dates in separate post_meta fields
     */
    public static function upgrade()
    {
    	$current_version = get_option("eventposttype_version");
		if ($current_version != self::$version) {
        	$allEvents = self::get_events();
        	if (count($allEvents)) {
    	    	foreach ($allEvents as $event) {
    		    	$old_meta = get_post_meta($event->ID, 'eventmeta', true);
    			    if ($old_meta != "") {
			            add_post_meta($event->ID, 'event_start', $old_meta["start_datetime"], true) or update_post_meta($event->ID, 'event_start', $old_meta["start_datetime"]);
			            add_post_meta($event->ID, 'event_end', $old_meta["end_datetime"], true) or update_post_meta($event->ID, 'event_end', $old_meta["end_datetime"]);
			            add_post_meta($event->ID, 'event_allday', $old_meta["all_day"], true) or update_post_meta($event->ID, 'event_allday', $old_meta["all_day"]);
    			    }
   				    delete_post_meta($event->ID, 'eventmeta');
					delete_post_meta($event->ID, 'event_date');
    		    }
    	    }
			add_option("eventposttype_version", self::$version);
		}
    }

	/**
     * registers all actions in Wordpress API
	 */
	public static function register()
	{
	    /* back port event dates meta fields */
	    self::upgrade();
		/* register plugin admin options */
        add_action( 'admin_menu', array('EventPostType', 'add_plugin_admin_menu') );
        add_action( 'admin_init', array('EventPostType', 'register_plugin_options') );
		/* initialise custom post type */
		add_action( 'init', array('EventPostType', 'register_event_post_type') );
		/* add counts to the Right Now widget on the dashboard */
		add_action( 'right_now_content_table_end', array('EventPostType', 'add_event_counts') );
		add_action( 'right_now_discussion_table_end', array('EventPostType', 'add_pending_event_counts') );
		/* add filter to update messages */
        add_filter( 'post_updated_messages', array('EventPostType', 'updated_messages') );
        /* add contextual help */
        add_action( 'contextual_help', array('EventPostType', 'add_help_text'), 10, 3 );
        /* Use the admin_menu action to define custom editing boxes */
        add_action( 'admin_menu', array('EventPostType', 'add_custom_boxes') );
        /* Use the admin_print_scripts action to add scripts for custom boxes */
        add_action( 'admin_print_scripts', array('EventPostType', 'custom_boxes_scripts') );
        /* Use the admin_print_styles action to add CSS for custom boxes */
        add_action( 'admin_print_styles', array('EventPostType', 'custom_boxes_styles') );
        /* Use the save_post action to do something with the data entered */
        add_action( 'save_post', array('EventPostType', 'save_postdata') );
    	/* add a body class */
    	add_filter( 'body_class', array('EventPostType', 'add_body_class') );
        /* put new date column on events list table */
        add_action( 'manage_edit-event_columns', array('EventPostType', 'add_event_date_column') );
        add_action( 'manage_event_posts_custom_column', array('EventPostType', 'show_event_date_column') );
        add_filter( 'manage_edit-event_sortable_columns', array('EventPostType', 'date_column_register_sortable') );
        add_filter( 'request', array('EventPostType', 'date_column_orderby') );
        add_filter( 'parse_query', array('EventPostType', 'sort_events_by_event_date')) ;
    	/* add shortcode */
    	add_shortcode( 'events', array('EventPostType', 'events_shortcode') );
    	/* register Events Widget */
    	add_action( 'widgets_init', create_function('', 'return register_widget("Widget_EventsPostType");') );
    	/* add a page describing the use of the plugin */
    	add_action( 'admin_menu', array('EventPostType', 'add_help_page') );
        /* adds a link to the help page from the plugins page */
        add_filter( 'plugin_action_links', array('EventPostType', 'add_help_page_link'), 10, 2 );
	}

	/*
	 * adds a bit at the end of the content part of the Right Now widget
	 * on the dashboard to show event counts
	 */
    public static function add_event_counts()
    {
        $num_events = 0;
		$allEvents = self::get_events();
        foreach ($allEvents as $event) {
            if ($event->post_parent == 0 && $event->post_status == "publish") {
                $num_events++;
            }
        }
        $num = $num_events;
        $text = "Events";
        if ( current_user_can( 'edit_posts' ) ) {
            $num = '<a href="edit.php?post_type=event">' . $num . '</a>';
            $text = '<a href="edit.php?post_type=event">' . $text . '</a>';
        }
        echo '<tr>';
        echo '<td class="first b b-cats">' . $num . '</td>';
        echo '<td class="t cats">' . $text . '</td>';
        echo '</tr>';
    }
    
	/*
	 * adds a bit at the end of the discussion part of the Right Now widget
	 * on the dashboard to show pending event counts
	 */
    public static function add_pending_event_counts()
    {
        $num_events = 0;
		$allEvents = self::get_events();
        foreach ($allEvents as $event) {
            if ($event->post_parent == 0 && $event->post_status == "pending") {
                $num_events++;
            }
        }
        $num = $num_events;
        $text = "Pending";
        if ( current_user_can( 'edit_posts' ) ) {
            $num = '<a href="edit.php?post_status=pending&post_type=event">' . $num . '</a>';
            $text = '<a class="waiting" href="edit.php?post_status=pending&post_type=event">' . $text . '</a>';
        }
        echo '<tr>';
        echo '<td class="first b b-cats">' . $num . '</td>';
        echo '<td class="t cats">' . $text . '</td>';
        echo '</tr>';
    }
    
	/**
     * initialise Events post type
     */
    public static function register_event_post_type()
    {
    	if ( function_exists("register_post_type")) :
            $labels = array(
                'name' => _x('Events', 'events'),
                'singular_name' => _x('Event', 'event'),
                'add_new' => _x('Add New', 'event'),
                'add_new_item' => __('Add New Event'),
                'edit_item' => __('Edit Event'),
                'new_item' => __('New Event'),
                'view_item' => __('View Event'),
                'search_items' => __('Search Events'),
                'not_found' =>  __('No Events found'),
                'not_found_in_trash' => __('No Events found in Trash'),
                'parent_item_colon' => ''
            );
            $args = array(
                'labels' => $labels,
                'public' => true,
                'has_archive' => true,
                'menu_position' => 20,
                'menu_icon' => plugins_url('/img/EventPostType.png', __FILE__),
                'rewrite' => array('slug' => 'events', 'with_front' => false),
                'supports' => array('title','editor','excerpt','thumbnail'),
                'taxonomies' => array( 'category', 'post_tag' )
            );
            register_post_type('event',$args);
        endif;
    }
    
    /**
     * update messages so the word Event appears in them
     */
    public static function updated_messages( $messages )
    {
        global $post, $post_ID;
        $messages['event'] = array(
            0 => '', // Unused. Messages start at index 1.
            1 => sprintf( __('Event updated. <a href="%s">View event</a>'), esc_url( get_permalink($post_ID) ) ),
            2 => __('Custom field updated.'),
            3 => __('Custom field deleted.'),
            4 => __('Event updated.'),
            /* translators: %s: date and time of the revision */
            5 => isset($_GET['revision']) ? sprintf( __('Event restored to revision from %s'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
            6 => sprintf( __('Event published. <a href="%s">View event</a>'), esc_url( get_permalink($post_ID) ) ),
            7 => __('Event saved.'),
            8 => sprintf( __('Event submitted. <a target="_blank" href="%s">Preview event</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
            9 => sprintf( __('Event scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview event</a>'),
            // translators: Publish box date format, see http://php.net/date
            date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ),
            10 => sprintf( __('Event draft updated. <a target="_blank" href="%s">Preview event</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
        );
        return $messages;
    }
    /**
     * display contextual help for Events
     */
    public static function add_help_text($contextual_help, $screen_id, $screen)
    {
        if ('event' == $screen->id ) {
            $contextual_help =
                '<p>Things to remember when adding or editing a event:</p>' .
                '<ul>' .
                '<li>Make sure you set the event start and end dates/times.</li>' .
                '<li>If any images, sound or other media is being uploaded for the event, always do so from the Add Media links on the Event editing page.</li>' .
                '</ul>' .
                '<p>If you want to schedule the event to be published in the future:</p>' .
                '<ul>' .
                '<li>In the Publish box on the right, click on the Edit link next to <strong>Status</strong> (Draft, Pending Review or Published).</li>' .
                '<li>Change the date to the date to actual publish this article, select Published from the list, then click on Ok.</li>' .
                '</ul>' .
                '<p><strong>For more information:</strong></p>' .
                '<p><a href="#">RTFM</a></p>' .
                '<p><a href="http://codex.wordpress.org/Posts_Edit_SubPanel" target="_blank">Edit Posts Documentation</a></p>' .
                '<p><a href="http://wordpress.org/support/" target="_blank">Support Forums</a></p>' ;
        } elseif ( 'edit-event' == $screen->id ) {
            $contextual_help =
                '<p>This list is automatically ordered using the settings for the event start and end dates.</p>';
        }
        return $contextual_help;
    }

    /**
     * adds a column to the events listing table
     * hooks into 'manage_edit-event_columns'
     * @param array $posts_columns
     * @return array $new_columns
     */
    public static function add_event_date_column( $posts_columns )
    {
		$new_columns['cb'] = '<input type="checkbox" />';
 		$new_columns['title'] = 'Event title';
		$new_columns['categories'] = 'Categories';
		$new_columns['event_date'] = 'Event Date';
		return $new_columns;
    }
    
   	/**
     * shows the event date column of the manage events table
     * hooks into 'manage_posts_custom_column'
     * @param $column_id
     * @param $post_id
     */
    public static function show_event_date_column( $column_id )
    {
    	global $post;
    	if ($column_id == "event_date") {
        	echo self::get_date($post->ID);
        }
    }
    
    /**
     * registers the date column as sortable
     * @param $columns array of sortable columns
     * @return new array of sortabkle columns with the event_date column added
     */
    public static function date_column_register_sortable( $columns )
    {
    	$columns["event_date"] = "event_date";
    	return $columns;
    }
    
    /**
     * enables Wordpress to order the event listing table
     * by the event_date column
     */
    public static function date_column_orderby( $vars )
    {
    	if (isset($vars["orderby"]) && $vars["orderby"] == "event_date") {
    		$vars = array_merge ($vars, array(
    		    "meta_key" => "event_start",
    		    "orderby" => "meta_value_num"
    		));
    	}
    	return $vars;
   	}

    /**
     * this is used to sort events by event date on the manage events
     * page in admin. It hooks into the filter "request" and adds extra
     * parameters to $query_vars when necessary 
     * @param $query
     */
    public static function sort_events_by_event_date($query)
    {
        global $pagenow;
        if (is_admin() && $pagenow=='edit.php' && $query->query_vars['post_type'] == 'event' && !isset($query->query_vars['orderby']))  {
            $query->query_vars['orderby'] = 'meta_value_num';
            $query->query_vars['meta_key'] = 'event_start';
            $query->query_vars['order'] = 'DESC';
        }
        return $query;
    }
    
    /*
     * Adds custom sections to the event edit screens
     */
    public static function add_custom_boxes()
    {
        add_meta_box( 'event_dates', 'Event Dates', array('EventPostType', 'event_dates_custom_box'), 'event', 'side', 'high' );
    }

    /**
     * Adds scripts to the admin pages for the events start and end datepicker
     */
    public static function custom_boxes_scripts()
    {
    	wp_register_script('eventsScript', plugins_url('/js/EventPostType.js', __FILE__), array('jquery'));
    	wp_enqueue_script('eventsScript');
        wp_register_script('anytime', plugins_url('/js/anytimec.js', __FILE__), array('jquery'));
        wp_enqueue_script('anytime');
    }

    /**
     * Adds CSS to the admin pages for the events start and end datepicker
     */
    public static function custom_boxes_styles()
    {
        wp_register_style('eventsStyle', plugins_url('/css/EventPostType.css', __FILE__));
        wp_register_style('anytime', plugins_url('/css/anytimec.css', __FILE__));
        wp_enqueue_style('eventsStyle');
        wp_enqueue_style('anytime');
    }
    /**
     * extracts post_meta for a given post
     * @param int post ID
     * @return array
     */
    public static function get_event_meta($postID)
    {
    	$meta = array("event_start" => "", "event_end" => "", "event_allday" => "");
    	$meta["event_start"] = get_post_meta($postID, 'event_start', true);
    	$meta["event_end"] = get_post_meta($postID, 'event_end', true);
		$meta["event_allday"] = (bool) get_post_meta($postID, 'event_allday', true);
        return $meta;
    }
    /**
     * Prints the fields for the custom date input sections of event pages
     */
    public static function event_dates_custom_box()
    {
        global $post;
        $event_data = self::get_event_meta($post->ID);
		$start_date = $event_data["event_start"]? date("d/m/Y", $event_data["event_start"]): date("d/m/Y");
		$start_time = $event_data["event_start"]? date("h:iA", $event_data["event_start"]): "12:00PM";
		$end_date = $event_data["event_end"]? date("d/m/Y", $event_data["event_end"]): "";
		$end_time = $event_data["event_end"]? date("h:iA", $event_data["event_end"]): "";
		
        /* Use nonce for verification */
        echo '<input type="hidden" name="event_dates" id="event_dates" value="' .  wp_create_nonce('events_custom_dates') . '" />';
        /* The actual fields for data entry */
        echo '<p id="event_dates_start" class="event_datep"><label for="event_dates_start_date">Event start</label><br />';
        echo '<input type="text" id="event_dates_start_date" name="event_dates_start_date" value="' . $start_date . '" size="25" class="datepicker" />';
        echo '<input type="text" id="event_dates_start_time" name="event_dates_start_time" value="' . $start_time . '" size="25" class="timepicker" /></p>';
        $checked = $event_data["event_allday"]? ' checked="checked"': '';
        echo '<p id="event_dates_duration" class="event_datep"><label for="event_dates_allday">All Day?</label><input type="checkbox" id="event_dates_allday" name="event_dates_allday"' . $checked . '>';
        echo '<select name="event_dates_duration_minutes" id="event_dates_duration_minutes"><option value="null" selected="selected">duration&hellip;</option>';
        for ($i = 1; $i < 13; $i++) {
            $hoursTotal = floor(($i * 30) / 60);
            $hoursStr = $hoursTotal == 1? " hour ": " hours ";
            $optionValue = $hoursTotal > 0? $hoursTotal . $hoursStr: "";
            $optionValue .= ($i % 2 != 0)? "30 minutes": "";
            echo '<option value="' . ($i * 30) . '">' . $optionValue . '</option>';
        }
        echo '</select></p>';
        echo '<p id="event_dates_end" class="event_datep"><label for="event_dates_end_date">Event end</label><br />';
        echo '<input type="text" id="event_dates_end_date" name="event_dates_end_date" value="' . $end_date . '" size="25" class="datepicker" />';
        echo '<input type="text" id="event_dates_end_time" name="event_dates_end_time" value="' . $end_time . '" size="25" class="timepicker" /></p>';
		echo '<p class="event_datep"></p>';
    }

    
    /**
     * Saves data from all custom sections
     */
    public static function save_postdata( $post_id )
    {
        if ( isset($_POST['post_type']) && 'event' == $_POST['post_type'] ) {
            /* verify this came from the our screen and with proper authorization */
            if ( !wp_verify_nonce( $_POST['event_dates'], 'events_custom_dates' )) {
                return $post_id;
            }
            /* verify if this is an auto save routine.
             * If it is our form has not been submitted, so we dont want to do anything
             */
            if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) {
                return $post_id;
            }
            /* Check permissions */
            if ( !current_user_can( 'edit_page', $post_id ) ) {
                return $post_id;
            }
            /* save event dates in post_meta */
            $start_date = isset($_POST['event_dates_start_date'])? $_POST['event_dates_start_date']: "";
            $start_time = isset($_POST['event_dates_start_time'])? $_POST['event_dates_start_time']: "";
            $end_date = isset($_POST['event_dates_end_date'])? $_POST['event_dates_end_date']: "";
            $end_time = isset($_POST['event_dates_end_time'])? $_POST['event_dates_end_time']: "";
            $event_start = self::parse_date($start_date, $start_time);
            $event_end = self::parse_date($end_date, $end_time);
            $event_allday = isset($_POST["event_dates_allday"]);
            add_post_meta($post_id, 'event_start', $event_start, true) or update_post_meta($post_id, 'event_start', $event_start);
			add_post_meta($post_id, 'event_end', $event_end, true) or update_post_meta($post_id, 'event_end', $event_end);
			add_post_meta($post_id, 'event_allday', $event_allday, true) or update_post_meta($post_id, 'event_allday', $event_allday);
        }
    }

    /**
     * parses dates/times
     * @param string date/time formatted as dd/mm/yyyy hh:mm
     * @return integer UNIX timestamp
     */
    public static function parse_date($datestr = "", $timestr = "")
    {
        if (trim($datestr) !== "") {
      	    if (preg_match("|([0-9]+)/([0-9]+)/([0-9]+)|", trim($datestr), $matches)) {
      	    	$year = intval($matches[3]);
      	    	$month = intval($matches[2]);
      	    	$day = intval($matches[1]);
      	    	$hour = 0;
      	    	$minute = 0;
      	    	$second = 0;
      	    	if (trim($timestr) !== "") {
      	    		if (preg_match("/([0-9]+):([0-9]+)(AM|PM)/", trim($timestr), $tmatches)) {
      	    			$hour = intval($tmatches[1]);
      	    			$minute = intval($tmatches[2]);
      	    			if ($tmatches[3] == "PM" && $hour < 12) {
      	    				$hour += 12;
      	    			}
      	    		}
      	    	}
                $datetime = @mktime($hour, $minute, $second, $month, $day, $year);
                if ($datetime !== false) {
                	return $datetime;
                }
            }
        }
        return "";
    }
	

    /**
     * Display logic methods
     */
    
	/**
	 * get_date
	 * returns a text representation of a date for an event
	 */
	public static function get_date($event_id, $display_options = array())
	{
    	$default_display_options = array(
		    "date_fmt" => "j/n/Y",
		    "time_fmt" => "g.ia",
		    "date_time_separator" => " | ",
		    "time_separator" => " &mdash; ",
		    "date_separator" => " &mdash; ",
			"allday" => " (all day)",
			"date_label" => "Date: ",
			"time_label" => "Time: "
		);
		$options = wp_parse_args($display_options, $default_display_options);
    	$event_start = get_post_meta($event_id, 'event_start', true);
    	$event_end = get_post_meta($event_id, 'event_end', true);
		$event_allday = (bool) get_post_meta($event_id, 'event_allday', true);
    	$date_html = "";
        if ($event_start !== "") {
            if ($event_allday) {
            	/* all day event - only need start date */
            	$start_date = @date($options["date_fmt"], $event_start);
                $date_html = '<span class="event-date-label">' . $options["date_label"] . '</span><span class="event-start-date">' . $start_date . '</span><span class="event-allday">' . $options["allday"] . '</span>';
            } else {
            	/*
				 * either:
				 * - an event spanning multiple days
				 * - an event on a single day with time bracket specified
				 * - an event with only the start date set
			     */
            	$start_date = @date($options["date_fmt"], $event_start);
            	$start_time = @date($options["time_fmt"], $event_start);
            	$end_date = @date($options["date_fmt"], $event_end);
                $end_time = @date($options["time_fmt"], $event_end);
				if (!$start_date) {
					/* no start date set (nothing to display) */
					$date_html = "";
				} elseif (!$end_date) {
					/* no end date set - output start date and time */
					$date_html = '<span class="event-date-label">' . $options["date_label"] . '</span><span class="event-start-date">' . $start_date . '</span>' . $options["date_time_separator"];
					$date_html .= '<span class="event-time-label">' . $options["time_label"] . '</span><span class="event-start-time">' . $start_time . '</span>';
				} elseif ($start_date == $end_date) {
					/* start and end dates are on the same day */
                	$date_html = '<span class="event-date-label">' . $options["date_label"] . '</span><span class="event-start-date">' . $start_date . '</span>' . $options["date_time_separator"];
					$date_html .= '<span class="event-time-label">' . $options["time_label"] . '</span><span class="event-start-time">' . $start_time . '</span>' . $options["time_separator"] . '<span class="event-end-time">' . $end_time . '</span>';
                } else {
                	/* start and end dates on different days */
                	$date_html = '<span class="event-date-label">' . $options["date_label"] . '</span><span class="event-start-date">' . $start_date . '</span>' . $options["date_separator"] . '<span class="event-end-date">' . $end_date . '</span>';
                }
            }
        }
        return $date_html;
	}
    
    /**
     * adds a class to the body of the page
     */
    public static function add_body_class($classes)
    {
        global $wp_query;
        if (isset($wp_query->query_vars['post_type']) && $wp_query->query_vars["post_type"] == 'event') {
		    $classes[] = 'event';
		    if (is_single()) {
		    	$classes[] = 'single-event';
		        $event = self::get_event($wp_query->post->ID);
		        if ($event) {
    		        if ($event->meta["event_start"] > time()) {
	    	    	    $classes[] = 'future-event';
		            } elseif ($event->meta["event_end"] < time()) {
		        	    $classes[] = 'past-event';
		            } else {
		    	        $classes[] = 'current-event';
		            }
		        }
		    }
        }
	    return $classes;
    }
    
    /**
     * Determines whether the current view is an event archive.
     * @return true or false
     */
    public static function is_event() 
    {
	    global $wp_query;
	    /* check for events post type */
	    if ( isset($wp_query->query_vars['post_type'] ) && $wp_query->query_vars['post_type'] == "event") {
	    	return true;
	    }
	    return false;
	}

    /**
     * gets a feed of events
     */
    public static function get_events_feed($format = "json", $month = false, $year = false)
    {
    	/* get all events and filter on month and year if necessary */
    	$feedEvents = self::get_events_for($year, $month);
    	$events = array();
		if (count($feedEvents)) {
            foreach ($feedEvents as $event) {
    			$eventObj = new stdClass();
    			$eventObj->id = $event->ID;
    			$eventObj->title = $event->post_title;
    			$eventObj->allDay = ($event->meta["event_allday"])? true: false;
    			$eventObj->start = (intVal($event->meta["event_start"]) * 1000);
    			$eventObj->end = (intVal($event->meta["event_end"]) * 1000);
    			$eventObj->dateStr = self::get_date($event->ID);
    			$eventObj->url = get_permalink($event->ID);
    		    $event_categories = wp_get_post_categories($event->ID);
    		    $classes = array();
    		    foreach($event_categories as $c){
                	$cat = get_category( $c );
                	$classes[] = $cat->slug;
    		    }
    		    if (count($classes)) {
    		    	if (count($classes) == 1){
    		    		$eventObj->className = $classes[0];
    		    	} else {
    		    	    $eventObj->className = $classes;
    		    	}
    		    }
				$events[] = $eventObj;
            }
    	}
    	switch(strtolower($format))
        {
            case "json":
        		return json_encode($events);
        		break;
            default:
                return "";
            	break;
    	}
    }
    
    /**
     * gets HTML and script to include FullCalendar
     */
    public static function get_full_events_calendar($opts)
    {
    	$out = "<div id=\"events-calendar\"></div>\n";
    	$out .= "<script type=\"text/javascript\">\n";
    	$out .= "jQuery(function($){\n";
    	$out .= "  $('head').append('<link/>');\n";
    	$out .= "  var css = $('head').children(':last');\n";
    	$out .= "  css.attr({rel:'stylesheet',type:'text/css',href:'" . plugins_url("css/fullcalendar.css", __FILE__) . "'});\n";
    	$out .= "  $.getScript('" . plugins_url("js/fullcalendar.min.js", __FILE__) . "', function(){\n";
    	$out .= "    setTimeout('init_fullcalendar()', 250);\n";
    	$out .= "  });\n";
    	$out .= "});\n";
    	$out .= "function init_fullcalendar(){\n";
    	$out .= "  jQuery('#events-calendar').fullCalendar({events:'" . get_bloginfo("url") . "/events-feed'});\n";
    	$out .= "}\n";
    	$out .= "</script>\n";
    	return $out;
    }
	
    /**
     * gets HTML and script to include events calendar
     */
    public static function get_events_calendar($opts = array())
    {
    	$days = array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday");
		$allEvents = self::get_events();
		if (isset($opts["ept_m"]) && isset($opts["ept_y"])) {
    	    $this_month = mktime(0, 0, 0, $opts["ept_m"], 1, $opts["ept_y"]);
	    	$prev_month = mktime(0, 0, 0, ($opts["ept_m"] - 1), 1, $opts["ept_y"]);
	    	$next_month = mktime(0, 0, 0, ($opts["ept_m"] + 1), 1, $opts["ept_y"]);
		} else {
    	    $this_month = mktime(0, 0, 0, date("n"), 1, date("Y"));
	    	$prev_month = mktime(0, 0, 0, (date("n") - 1), 1, date("Y"));
			$next_month = mktime(0, 0, 0, (date("n") + 1), 1, date("Y"));
		}
        $days_this_month = date("t", $this_month);
		$days_prev_month = date("t", $prev_month);
		$weekday = date('w', $this_month);
		$dow = 1;
    	/* generate a HTML based calendar for the current date */
    	$out = "<div id=\"eventsCalendar\">\n  <div class=\"ec-container\">\n";
		$out .= "    <h4>" . date("F Y", $this_month) . "</h4>\n";
        $out .= "    <div id=\"ec-calendar\">\n      <table cellspacing=\"2\" class=\"eventsCalendar\">\n        <thead>\n          <tr>";
        foreach ($days as $day) {
        	$class = (strpos($day, "S") === 0)? "weekend": "weekday";
        	$out .= sprintf('<th scope="col" abbr="%s" title="%s" class="%s">%s</th>', $day, $day, $class, substr($day, 0, 1));
        }
		$out .= "</tr>\n        </thead>\n        <tbody>\n";
		$out .= "          <tr>";
	    if ($weekday != 1) {
	    	/* month doesn't start on Monday - print dates from previous month */
	    	$offset = ($weekday == 0)? 5: -((1 - $weekday) + 1);
	    	for ($day = ($days_prev_month - $offset); $day <= $days_prev_month; $day++) {
	    		$today = mktime(0, 0, 0, date("n", $prev_month), $day, date("Y", $prev_month));
				$class = "other-month ";
				$class .= ($dow < 6)? "weekday": "weekend";
				$events = self::get_events_for(date("Y", $prev_month), date("n", $prev_month), $day);
				if (count($events)) {
					$titles = array();
					foreach ($events as $evt) {
						$titles[] = esc_attr($evt->post_title);
					}
					$title = implode(", ", $titles);
					$out .= '<td class="' . $class . ' eventday" title="' . $title . '"><a title="' . $title . '" href="?ept_d=' . $day . '&ept_m=' . date("n", $today) . '&ept_y=' . date("Y", $today) . '">' . $day . '</a></td>';
				} else {
					$out .= '<td class="' . $class . '">' . $day . '</td>';
				}
				$dow++;
	    	}
	    }
		/* print dayes for current month */
		for ($day = 1; $day <= $days_this_month; $day++) {
		    if($dow > 7) {
			    $dow = 1;
			    $out .= "</tr>\n          <tr>";
		    }
    		$today = mktime(0, 0, 0, date("n", $this_month), $day, date("Y", $this_month));
			$class = "current-month ";
			$class .= ($dow < 6)? "weekday": "weekend";
			$events = self::get_events_for(date("Y", $this_month), date("n", $this_month), $day);
			if (count($events)) {
    			$titles = array();
				foreach ($events as $evt) {
					$titles[] = esc_attr($evt->post_title);
				}
				$title = implode(", ", $titles);
				$out .= '<td class="' . $class . ' event" title="' . $title . '"><a title="' . $title . '" href="?ept_d=' . $day . '&ept_m=' . date("n", $today) . '&ept_y=' . date("Y", $today) . '">' . $day . '</a></td>';
			} else {
				$out .= '<td class="' . $class . '">' . $day . '</td>';
			}
			$dow++;
	    }
		if ($dow < 8) {
			$days_to_go = 8 - $dow;
			/* fill in remaining days from next month */
			for ($day = 1; $day <= $days_to_go; $day++) {
	    		$today = mktime(0, 0, 0, date("n", $next_month), $day, date("Y", $next_month));
				$class = "other-month ";
				$class .= ($dow < 6)? "weekday": "weekend";
				$events = self::get_events_for(date("Y", $next_month), date("n", $next_month), $day);
				if (count($events)) {
					foreach ($events as $evt) {
						$titles[] = esc_attr($evt->post_title);
					}
					$title = implode(", ", $titles);
					$out .= '<td class="' . $class . ' event" title="' . $title . '"><a title="' . $title . '" href="?ept_d=' . $day . '&ept_m=' . date("n", $today) . '&ept_y=' . date("Y", $today) . '">' . $day . '</a></td>';
				} else {
					$out .= '<td class="' . $class . '">' . $day . '</td>';
				}
				$dow++;
			}
		}
		$out .= "</tr>\n        </tbody>\n      </table>\n    </div>\n  </div>\n";	
    	$out .= "<script type=\"text/javascript\">\n";
    	$out .= "var eventsJSON = '" . get_bloginfo("url") . "/events/?f=json';\n";
    	$out .= "jQuery(function($){\n";
    	$out .= "  $('head').append('<link/>');\n";
    	$out .= "  var css = $('head').children(':last');\n";
    	$out .= "  css.attr({rel:'stylesheet',type:'text/css',href:'" . plugins_url("css/eventscalendar.css", __FILE__) . "'});\n";
    	$out .= "  $.getScript('" . plugins_url("js/eventscalendar.js", __FILE__) . "', function(){\n";
    	$out .= "  });\n";
    	$out .= "});\n";
    	$out .= "</script>\n</div>\n";
    	return $out;
    }
    
	/**
	 * checks to see if there are any events for a year, month or day
	 */
	public static function get_events_for($year = false, $month = false, $day = false)
	{		
	    /* get events */
		$allEvents = self::get_events();
		/* if called with no arguments, return all events */
		if ($year === false) {
			return $allEvents;
		}
		/* set start and end timestamps according to request */
		if ($day !== false && $month !== false) {
			/* a specific day has been requested */
			$start = mktime(0, 0, 0, $month, $day, $year);
			$end = mktime(0, 0, 0, $month, ($day + 1), $year);
		} elseif ($day === false && $month !== false) {
			/* a month has been requested */
			$start = mktime(0, 0, 0, $month, 1, $year);
			$end = mktime(0, 0, 0, ($month + 1), 1, $year);
		}
		/* store events for the given period in here */
		$events = array();
		/* loop through events and add today's events to the $events array */
    	if (count($allEvents)) {
    		foreach ($allEvents as $evt) {
    			/* see if event starts during the day specified */
    			if ($evt->meta["event_start"] && $evt->meta["event_start"] >= $start && $evt->meta["event_start"] < $end) {
    				$events[] = $evt;
				/* see if event ends during the day specified */
		        } elseif ($evt->meta["event_end"] && $evt->meta["event_end"] >= $start && $evt->meta["event_end"] < $end) {
		        	$events[] = $evt;
				}
			}
		}
		return $events;
	}
    
    /**
     * gets all events and event metadata
     * @return array
     */
    public static function get_events()
    {
    	$allEvents = wp_cache_get( 'allEvents' );
		if ($allEvents == false) {
        	$args = array(
        	  "numberposts" => -1,
    	      "post_type" => "event",
    	      "post_status" => "publish",
    	      "post_parent" => 0
    	    );
    	    /* get all events */
    	    $allEvents = get_posts($args);
    	    /* add custom meta */
    	    for ($i = 0; $i < count($allEvents); $i++) {
     		    $allEvents[$i]->meta = self::get_event_meta($allEvents[$i]->ID);
    	    }
    	    usort($allEvents, array("EventPostType", "sort_events_by_start_date"));
    	    wp_cache_set( 'allEvents', $allEvents);
		}
		return $allEvents;
    }

    /**
     * get_event
     * shorthand for getting a single event's data
     * @param $post_id
     * @return object
     */
    public static function get_event($post_id)
    {
    	$allEvents = self::get_events();
    	foreach ($allEvents as $event){
   	    	if ($event->ID == $post_id) {
    			return $event;
    		}
	    }
	    return false;
    }

    /**
     * comparison function to sort event pages by start date (in custom field)
     * @param object event $a
     * @param object event $b
     * @return integer
     */
    public static function sort_events_by_start_date($a, $b)
    {
	    if ($a->meta["event_start"] == $b->meta["event_start"]) return 0;
	    return ($a->meta["event_start"] < $b->meta["event_start"])? -1: 1;
    }
    
    /**
     * shortcode for events
     */
    public static function events_shortcode($atts)
    {
	    $opts = shortcode_atts( self::get_plugin_options(), $atts );
	    return self::format_events($opts);	
    }

    /**
     * function to retrieve a formatted list of events
     * @param array $options
     * @return array
     */
    public static function format_events($options = array())
    {
    	$allEvents = self::get_events();
    	if (!count($allEvents)) {
    		return "";
    	}
    	$opts = wp_parse_args($options, self::get_plugin_options());
    	/* see if a category has been requested */
    	if ($opts["category"]) {
    		/* split multiple categories at the comma */
    		if (strpos($opts["category"], ",") !== false) {
    		    $cat = explode(",", $opts["category"]);
			} else {
				$cat = $opts["category"];
			}
			$evt_temp = array();
			foreach ($allEvents as $evt) {
				if (in_category($cat, $evt->ID)) {
					$evt_temp[] = $evt;
				}
			}
			$allEvents = $evt_temp;
    	}
		/* sort events into upcoming and recent */
		$events = array("upcoming" => array(), "recent" => array());
    	for ($i = 0; $i < count($allEvents); $i++) {
            if ($allEvents[$i]->meta["event_start"] > time()) {
            	$events["upcoming"][] = $allEvents[$i];
            } else {
            	$events["recent"][] = $allEvents[$i];
            }
        }
		/* reverse recent events so most recent comes first */
		$events["recent"] = array_reverse($events["recent"]);
		/**
		 * remove events which are outside the parameters
		 */
        if ($opts['upcoming'] || $opts['upcoming'] === 0) {
        	/* if there are more upcoming events than the number specified, slice the array */
        	if (count($events["upcoming"]) > intval($opts['upcoming'])) {
        	    $events["upcoming"] = array_slice($events["upcoming"], 0, intval($opts['upcoming']));
        	}
        }
        if ($opts['recent'] || $opts['recent'] === 0) {
        	/* if there are more recent events than the number specified, slice the array */
        	if (count($events["recent"]) > $opts['recent']) {
        		$events["recent"] = array_slice($events["recent"], 0, $opts['recent']);
        	}
        }
        if (isset($opts['max']) && intval($opts['max']) > 0) {
        	/* if a maximum is specified, trim off the recent events first */
        	$total = count($events["recent"]) + count($events["upcoming"]);
        	if ($total > intval($opts['max'])) {
        		if (count($events["upcoming"]) < intval($opts['max'])) {
        			$events["recent"] = array_slice($events["recent"], 0, (intval($opts['max']) - count($events["upcoming"])));
        		} else {
        			$events["recent"] = array();
					$events["upcoming"] = array_slice($events["upcoming"], 0, intval($opts['max']));
        		}
        	}
        }
    	switch (strtolower($opts["format"])) {
			case "json":
    		    return self::get_events_feed();
				break;
            case "fullcalendar":
        		return self::get_full_events_calendar($opts);
        		break;
			case "calendar":
    		    return self::get_events_calendar($opts);
				break;
            case "raw":
                return $events;
				break;
    	}
    	$out = "";
		if (count($events["upcoming"])) {
	        if (!empty($opts['title_upcoming'])) {
   			    $out .= $opts['before_title'] . $opts['title_upcoming'] . $opts['after_title'];
			}
		    $out .= "<ul class=\"events-list upcoming-events\">\n";
		    foreach ($events["upcoming"] as $evt) {
		    	$out .= self::get_formatted_event($evt, $opts["format_upcoming"], $opts);
			}
			$out .= "\n</ul>\n";
		}
        if (count($events["recent"])) {
        	if (!empty($opts['title_recent'])) {
			    $out .= $opts['before_title'] . $opts['title_recent'] . $opts['after_title'];
		    }
		    $out .= "<ul class=\"events-list recent-events\">\n";
			foreach ($events["recent"] as $evt) {
		    	$out .= self::get_formatted_event($evt, $opts["format_recent"], $opts);
		    }
		    $out .= "\n</ul>\n";
		}
		return $out;
    }

    /**
	 * returns a single formatted event
	 */
	public static function get_formatted_event($evt, $format, $opts)
	{
		if (has_filter("event-format")) {
			return apply_filters("event-format", $evt, $opts);
		}
		switch ($format) {
			case "featured":
			case "long":
            	/* get the thumbnail for the event */
            	$thumb = "";
    	        if (has_post_thumbnail($evt->ID)) {
   		            if (!isset($opts["thumbnail_size"])) {
   		    	        $size = 'thumbnail';
   		            } else {
   		    	        if (preg_match("/([0-9]+),([0-9]+)/", $opts["thumbnail_size"], $matches)) {
   		    		        $size = array($matches[1], $matches[2]);
   		    	        } else {
   		    		        $size = $opts["thumbnail_size"];
   		    	        }
   		            }
   		            $thumbnail = get_the_post_thumbnail($evt->ID, $size);
					if ($thumbnail != "") {
   		                $thumb = sprintf('<a href="%s" title="%s">%s</a>', get_permalink($evt->ID), esc_attr($evt->post_title), $thumbnail);
       	            }
				}
		    	if ($format == "featured") {
		    		return sprintf('<li>%s<h3><a href="%s" title="%s">%s</a></h3><p class="eventdate">%s</p>%s</li>', $thumb, get_permalink($evt->ID), esc_attr($evt->post_title), esc_attr($evt->post_title), self::get_date($evt->ID, $opts), apply_filters("the_excerpt", $evt->post_excerpt));
		    	} elseif ($format == "long") {
		    		return sprintf('<li>%s<h3><a href="%s" title="%s">%s</a></h3><p class="eventdate">%s</p>%s</li>', $thumb, get_permalink($evt->ID), esc_attr($evt->post_title), esc_attr($evt->post_title), self::get_date($evt->ID, $opts), apply_filters("the_content", $evt->post_content));
		    	}
			    break;
            case "short":
                return sprintf('<li><h3><a href="%s" title="%s">%s</a></h3><p class="eventdate">%s</p>%s</li>', get_permalink($evt->ID), esc_attr($evt->post_title), esc_attr($evt->post_title), self::get_date($evt->ID, $opts), apply_filters("the_excerpt", $evt->post_excerpt));
                break;
			default:
				return sprintf('<li><a href="%s" title="%s">%s</a><br />%s</li>', get_permalink($evt->ID), esc_attr($evt->post_title), esc_attr($evt->post_title), self::get_date($evt->ID, $opts));
                break;
        }
	}

    /**
     * adds a menu item to tools
     */
    public static function add_help_page()
    {
    	add_submenu_page('tools.php', 'events-shortcode-help', 'Events shortcode', 'edit_posts', 'events-shortcode-help', array('EventPostType', 'help_page') );
    }
    /**
     * prints a help page which is added to the Wordpress Tools menu
     */
    public static function help_page()
    {
    	$out = file_get_contents(dirname(__FILE__) . "/doc/shortcode.html");
    	print($out);
    }
    
    /**
     * adds a link to the help page from the plugins listing page
     * called using the plugin_action_links filter
     */
    public static function add_help_page_link($links, $file)
    {
        if ($file == plugin_basename(__FILE__)) {
            $help_page_link = '<a href="tools.php?page=events-shortcode-help">Help</a>';
            array_unshift($links, $help_page_link);
        }
        return $links;
    }
	
	/************************************************************
	 * PLUGIN OPTIONS ADMINISTRATION                            *
	 ************************************************************/
	
    /**
     * add a submenu to the theme admin menu to access the theme settings page
     */
    public static function add_plugin_admin_menu()
    {
        /* Plugin Options page */
        $options_page = add_submenu_page("edit.php?post_type=event", "Events Options", "Events Options", "manage_options", "event_options", array('EventPostType', "plugin_options_page") );
        /* Use the admin_print_scripts action to add scripts for theme options */
        add_action( 'admin_print_scripts-' . $options_page, array('EventPostType', 'plugin_admin_scripts') );
        /* Use the admin_print_styles action to add CSS for theme options */
        //add_action( 'admin_print_styles-' . $options_page, array('EventPostType', 'ept_admin_styles') );
    }

    /**
     * add script to admin for plugin options
     */
    public static function plugin_admin_scripts()
    {
        wp_enqueue_script('EventPostTypeAdminScript', plugins_url('js/EventPostTypeAdmin.js', __FILE__), array('jquery'));
    }
	
    /**
     * registers settings and sections
     */
    function register_plugin_options()
    {
        register_setting('ept_plugin_options', 'ept_plugin_options', array('EventPostType', 'validate_ept_plugin_options'));
        /* taxonomy options */
        add_settings_section('taxonomy-options', 'Taxonomy Options', array('EventPostType', 'ept_section_text'), 'ept');
        add_settings_field('event_taxonomies', 'Choose which taxonomies to use for Events', array('EventPostType', 'ept_setting_taxonomies'), 'ept', 'taxonomy-options', array("fieldname" => "event_taxonomies", "description" => "This will allow you to use Categories, Tags or Custom taxonomies for the Events post type"));
                
        /* archive page options */
        add_settings_section('archive-options', 'Events Archive Options', array('EventPostType', 'ept_section_text'), 'ept');
        add_settings_field('archive_upcoming', 'Number of upcoming events to display', array('EventPostType', 'ept_setting_number'), 'ept', 'archive-options', array("fieldname" => "archive_upcoming", "description" => "This will limit the number of upcoming events displayed on the archive page"));
        add_settings_field('archive_perpage', 'Number of events per page', array('EventPostType', 'ept_setting_number'), 'ept', 'archive-options', array("fieldname" => "archive_perpage", "description" => "Number of events displayed per page in the archive"));

		/* widget/shortcode options */
        add_settings_section('widget-options', 'Shortcode/Widget Options', array('EventPostType', 'ept_section_text'), 'ept');
        add_settings_field('title_upcoming', 'Upcoming Events Title', array('EventPostType', 'ept_setting_text'), 'ept', 'widget-options', array("fieldname" => "title_upcoming", "description" => ""));
        add_settings_field('upcoming', 'Number of upcoming events to display', array('EventPostType', 'ept_setting_number'), 'ept', 'widget-options', array("fieldname" => "upcoming", "description" => ""));
		add_settings_field('format_upcoming', 'Format of upcoming events list', array('EventPostType', 'ept_setting_format'), 'ept', 'widget-options', array("fieldname" => "format_upcoming", "description" => ""));
        add_settings_field('title_recent', 'Recent Events Title', array('EventPostType', 'ept_setting_text'), 'ept', 'widget-options', array("fieldname" => "title_recent", "description" => ""));
        add_settings_field('recent', 'Number of recent events to display', array('EventPostType', 'ept_setting_number'), 'ept', 'widget-options', array("fieldname" => "recent", "description" => ""));
		add_settings_field('format_recent', 'Format of recent events list', array('EventPostType', 'ept_setting_format'), 'ept', 'widget-options', array("fieldname" => "format_recent", "description" => ""));
        add_settings_field('thumbnail_size', 'Thumbnail to use in longer listing formats', array('EventPostType', 'ept_setting_thumbnail'), 'ept', 'widget-options', array("fieldname" => "thumbnail_size"));
        add_settings_field('max', 'Maximum number of events to display', array('EventPostType', 'ept_setting_number'), 'ept', 'widget-options', array("fieldname" => "max", "description" => ""));
        
		/* date format options */
        add_settings_section('date-options', 'Date Format Options', array('EventPostType', 'ept_section_date'), 'ept');
        add_settings_field('date_fmt', 'Date format', array('EventPostType', 'ept_setting_dateformat'), 'ept', 'date-options', array("fieldname" => "date_fmt", "description" => "Use format strings for the <a href=\"http://www.php.net/manual/en/function.date.php\">PHP <code>date()</code> function</a> here"));
        add_settings_field('time_fmt', 'Time format', array('EventPostType', 'ept_setting_dateformat'), 'ept', 'date-options', array("fieldname" => "time_fmt", "description" => "Use format strings for the <a href=\"http://www.php.net/manual/en/function.date.php\">PHP <code>date()</code> function</a> here"));
        add_settings_field('date_label', 'Date label', array('EventPostType', 'ept_setting_dateformat'), 'ept', 'date-options', array("fieldname" => "date_label", "description" => "Text used as a label preceding a date"));
        add_settings_field('time_label', 'Time label', array('EventPostType', 'ept_setting_dateformat'), 'ept', 'date-options', array("fieldname" => "time_label", "description" => "Text used as a label preceding a time"));
        add_settings_field('date_time_separator', 'Date/Time separator', array('EventPostType', 'ept_setting_dateformat'), 'ept', 'date-options', array("fieldname" => "date_time_separator", "description" => "Text used to separate dates and times"));
        add_settings_field('date_separator', 'Date separator', array('EventPostType', 'ept_setting_dateformat'), 'ept', 'date-options', array("fieldname" => "date_separator", "description" => "Text used to separate two dates when an event spans multiple days"));
        add_settings_field('time_separator', 'Time separator', array('EventPostType', 'ept_setting_dateformat'), 'ept', 'date-options', array("fieldname" => "time_separator", "description" => "Text used to separate two times when an event takes place between two times on the same day"));
        add_settings_field('allday', 'All day event indicator', array('EventPostType', 'ept_setting_dateformat'), 'ept', 'date-options', array("fieldname" => "allday", "description" => "Text placed after a date for an all day event"));
    }

    /**
	 * gets plugin options - merges saved options with defaults
     * @return array
     */
    public static function get_plugin_options()
	{
        $defaults = array(
            "title" => '',
            "taxonomies" => array("category", "post_tag"),
            "upcoming" => false,
            "title_upcoming" => "Upcoming Events",
            "format_upcoming" => "list",
            "recent" => false,
            "title_recent" => "Recent Events",
            "format_recent" => "list",
            "thumbnail_size" => "thumbnail",
            "max" => 10,
            "category" => false,
            "date" => false,
            "format" => "list",
            "before_title" => "<h3>",
            "after_title" => "</h3>",
		    "date_fmt" => "j/n/Y",
		    "time_fmt" => "g.ia",
		    "date_time_separator" => " | ",
		    "time_separator" => " &ndash; ",
		    "date_separator" => " &ndash; ",
			"allday" => " (all day)",
			"date_label" => "Date: ",
			"time_label" => "Time: ",
			"ept_m" => false,
			"ept_y" => false,
			"ept_d" => false,
			"archive_upcoming" => 4,
			"archive_perpage" => 8
        );
		$saved = get_option('ept_plugin_options');
		return wp_parse_args($saved, $defaults);
	}

    /**
     * creates the options page
     */
    public static function plugin_options_page()
    {
        print("<div class=\"wrap\"><div class=\"icon32\" id=\"icon-options-general\"><br /></div><h2>Events Options</h2>");
        settings_errors('ept_plugin_options');
        if (isset($_REQUEST['settings-updated']) && $_REQUEST['settings-updated'] == "true")
        {
            echo '<div id="message" class="updated"><p><strong>Settings saved.</strong></p></div>';
        }
        print("<form method=\"post\" action=\"options.php\">\n");
        settings_fields('ept_plugin_options');
        do_settings_sections('ept');
        printf("<p class=\"submit\"><input type=\"submit\" class=\"button-primary\" name=\"Submit\" value=\"%s\" /></p>", _('Save Changes'));
        print("</form></div>");
    }

    /**
     * settings section text
     */
    public static function ept_section_text()
        { echo ""; }

    /**
     * settings section text
     */
    public static function ept_section_date()
        { echo "<div id=\"date_preview\"></div>"; }

    /**
     * input for text
     */
    public static function ept_setting_text($args)
    {
        $options = self::get_plugin_options();
		$field = $args["fieldname"];
		$option_value = (isset($options[$field ]) && trim($options[$field ]) != "")? trim($options[$field ]): "";
        printf('<input id="%s" name="ept_plugin_options[%s]" type="text" value="%s" size="20" />', $field, $field, $option_value);
		if (isset($args["description"]) && $args["description"] != "") {
			print("<p><em>" . $args["description"] . "</em></p>");
		}
    }
	
    /**
     * input for date format text
     */
    public static function ept_setting_dateformat($args)
    {
        $options = self::get_plugin_options();
		$field = $args["fieldname"];
		$option_value = (isset($options[$field]))? htmlentities($options[$field]): "";
        printf('<input class="dateformat" id="%s" name="ept_plugin_options[%s]" type="text" value="%s" size="10" />', $field, $field, $option_value);
		if ($field == 'date_fmt' || $field == 'time_fmt') {
			/* example date/time */
			$ts = mktime(13,45,0,date("n"),date("j"),date("Y"));
			/* date format examples */
			$examples = array(
			    "date_fmt" => array("d/m/Y", "j/n/Y", "d.m.Y", "j.n.Y", "M j, Y", "M jS, Y", "F j, Y", "F jS, Y", "jS M, Y", "jS F, Y", "l jS F, Y", "D jS F, Y"),
			    "time_fmt" => array("g:ia", "g.ia", "g:iA", "g.iA", "h:ia", "h.ia", "h:iA", "h.iA", "G:i", "G.i")
			);
			print('<select id="ex_' . $field . '" class="format-examples"><option value="" selected="selected">Examples...</option>');
			foreach ($examples[$field] as $ex) {
				printf('<option value="%s">%s</option>', $ex, date($ex, $ts));
			}
			print('</select>');
		}
		if (isset($args["description"]) && $args["description"] != "") {
			print("<p><em>" . $args["description"] . "</em></p>");
		}
    }

    /**
     * input for number
     */
    public static function ept_setting_number($args)
    {
        $options = self::get_plugin_options();
		$field = $args["fieldname"];
        $option_value = (isset($options[$field]) && $options[$field] != "")? intval($options[$field]): "";
        printf('<input id="%s" name="ept_plugin_options[%s]" type="text" value="%s" size="2" />', $field, $field, $option_value);
		if (isset($args["description"]) && $args["description"] != "") {
			print("<p><em>" . $args["description"] . "</em></p>");
		}
    }

    /**
     * input field for format
     */
    public static function ept_setting_format($args)
    {
    	$options = self::get_plugin_options();
		$field = $args["fieldname"];
        $option_value = (isset($options[$field]) && $options[$field] != "")? intval($options[$field]): "";
        print self::get_format_select($field, "ept_plugin_options[" . $field . "]", $option_value);
    }

	/**
	 * gets a select list of output formats
	 * checks to see if a filter has been registered on "event-format"
	 */
	public static function get_format_select($id, $name, $selected = "list")
	{
		$formats = array(
		    "list" => "Title and date",
		    "short" => "Title, date and excerpt",
		    "featured" => "Post thumbnail, title, date and excerpt",
		    "full" => "Title, date and full content"
		);
		$out = "";
		if (!has_filter("event-format")) {
		    $out .= '<ul>';
		    $suffix = "";
		    foreach ($formats as $fmt => $desc) {
			    $id .= $suffix;
			    $chckd = ($fmt == $selected)? ' checked="checked"': '';
			    $out .= sprintf('<li><input type="radio" name="%s" id="%s" value="%s"%s />%s</li>', $name, $id, $fmt, $chckd, $desc);
			    $suffix .= "_";
		    }
		    $out .= '</ul>';
	        return $out;
		} else {
			$out .= sprintf('(User defined) <input type="hidden" name="%s" id="%s" value="user" />', $name, $id);
		}
	    return $out;
	}
	
	/**
	 * set size og thumbnail to use in longer listing formats
	 */
	public static function ept_setting_thumbnail()
	{
    	$options = self::get_plugin_options();
        $option_value = (isset($options['thumbnail_size']) && $options['thumbnail_size'] != "")? $options['thumbnail_size']: "";
		if (!has_filter("event-format")) {
			$sizes = get_intermediate_image_sizes();
			print('<select id="thumbnail_size_select" name="thumbnail_size_select">');
			foreach ($sizes as $size) {
				$sel = $option_value == $size? ' selected="selected"': '';
				printf('<option value="%s"%s>%s</option>', $size, $sel, $size);
			}
			$sel = !in_array($option_value, $sizes)? ' selected="selected"': '';
			$custom_value = !in_array($option_value, $sizes)? $option_value: '';
			printf('<option value="custom"%s>Custom&hellip;</option></select><br /><input type="text" name="thumbnail_size_input" id="thumbnail_size_input" size="7" value="%s" />', $sel, $custom_value);
		} else {
			$option_value = "user";
			print('(User defined)');
		}
		printf('<input type="hidden" id="ept_plugin_options_thumbnail_size" name="ept_plugin_options[thumbnail_size]" value="%s" />', $option_value);
		print("<p id=\"custom_thumbnail_desc\"><em>Custom settings consist of two numbers separated by a comma.<br />These represent the width and height of the cropped image.</em></p>");
	}

    /**
     * set which taxonomies to use for Events
     */
	public static function ept_setting_taxonomies()
	{
    	$options = self::get_plugin_options();
    	$taxonomies = get_taxonomies(array('public' => true), 'objects');
	    foreach ($taxonomies as $taxonomy ) {
	    	$chckd = in_array($taxonomy->name, $options["taxonomies"])? ' checked="checked"': '';
            printf('<p><input type="checkbox" name="ept_plugin_options[taxonomies][]" value="%s"%s />%s</p>', $taxonomy->name, $chckd, $taxonomy->label);
        }
	}
	
    /**
     * input validation callback
     */
    public static function validate_ept_plugin_options($ept_plugin_options)
    {
        return $ept_plugin_options;
    }

} /* end class definition */
/* initialise */
EventPostType::register();
endif;

/**
 * widget for events
 */
class Widget_EventsPostType extends WP_Widget {

	function Widget_EventsPostType() {
		$widget_ops = array('classname' => 'widget_eventslist', 'description' => 'A list of upcoming and recent Events' );
		$this->WP_Widget('events_list', 'Events Listing', $widget_ops);
	}

	function widget( $args, $instance )
	{
		global $post;
		if (EventPostType::is_event() || ($post && $post->post_title == "Events")) {
			return;
		}
		extract($args);
		echo $before_widget;
		echo '<div id="events_widget_wrap">';
		echo EventPostType::format_events($instance);
		echo '</div>';
		echo $after_widget;
	}

	function update( $new_instance, $old_instance ) {
		$instance = $old_instance;
		$instance['title_upcoming'] = strip_tags($new_instance['title_upcoming']);
		$instance['format_upcoming'] = $new_instance['format_upcoming'];
		$instance['title_recent'] = strip_tags($new_instance['title_recent']);
		$instance['format_recent'] = $new_instance['format_recent'];
		$instance['upcoming'] = intVal($new_instance['upcoming']);
        $instance['recent'] = intVal($new_instance['recent']);
        $instance['max'] = intVal($new_instance['max']) > 0? intVal($new_instance['max']): '';
        return $instance;
	}

	function form( $instance )
	{
		global $ept;
		$instance = extract(wp_parse_args( (array) $instance, EventPostType::get_plugin_options() ));
?>
		<p><label for="<?php echo $this->get_field_id('title_upcoming'); ?>">Upcoming events title:</label>
		<input maxlength="45" size="20" id="<?php echo $this->get_field_id('title_upcoming'); ?>" name="<?php echo $this->get_field_name('title_upcoming'); ?>" type="text" value="<?php echo esc_attr($title_upcoming); ?>" /></p>

        <p><label for="<?php echo $this->get_field_id('upcoming'); ?>">Number of upcoming events to show:</label>
		<?php echo $this->get_number_select($this->get_field_id('upcoming'), $this->get_field_name('upcoming'), intVal($upcoming)); ?></p>
		
        <?php if (!has_filter("event-format")) : ?>
        <p><label for="<?php echo $this->get_field_id('format_upcoming'); ?>">Format for upcoming events:</label>
		<?php echo EventPostType::get_format_select($this->get_field_id('format_upcoming'), $this->get_field_name('format_upcoming'), $format_upcoming); ?></p>
        <?php else: ?>
		<input type="hidden" name="<?php echo $this->get_field_name('format_upcoming'); ?>" id="<?php echo $this->get_field_id('format_upcoming'); ?>" value="list" />
        <?php endif; ?>

		<p><label for="<?php echo $this->get_field_id('title_recent'); ?>">Recent events title:</label>
		<input maxlength="45" size="20" id="<?php echo $this->get_field_id('title_recent'); ?>" name="<?php echo $this->get_field_name('title_recent'); ?>" type="text" value="<?php echo esc_attr($title_recent); ?>" /></p>

        <p><label for="<?php echo $this->get_field_id('recent'); ?>">Number of recent events to show:</label>
		<?php echo $this->get_number_select($this->get_field_id('recent'), $this->get_field_name('recent'), intVal($recent)); ?></p>
        
        <?php if (!has_filter("event-format")) : ?>
        <p><label for="<?php echo $this->get_field_id('format_recent'); ?>">Format for recent events:</label>
		<?php echo EventPostType::get_format_select($this->get_field_id('format_recent'), $this->get_field_name('format_recent'), $format_recent); ?></p>
        <?php else: ?>
		<input type="hidden" name="<?php echo $this->get_field_name('format_recent'); ?>" id="<?php echo $this->get_field_id('format_recent'); ?>" value="list" />
        <?php endif; ?>

        <p><label for="<?php echo $this->get_field_id('max'); ?>">Maximum number of events to show:</label>
		<?php echo $this->get_number_select($this->get_field_id('max'), $this->get_field_name('max'), intVal($max)); ?></p>
<?php
	}
	
	function get_number_select($id, $name, $selected, $max = 10)
	{
		$out = sprintf('<select name="%s" id="%s"><option value="0"></option>', $name, $id);
		for ($i = 1; $i <= $max; $i++) {
			$sel = $i == $selected? ' selected="selected"': '';
			$out .= sprintf('<option value="%s"%s>%s</option>', $i, $sel, $i);
		}
		$out .= '</select>';
		return $out;
	}
	
}

